package keqiang.com.kq_flutter_core_widget.channel;

import android.app.Activity;
import android.content.Intent;
import android.provider.MediaStore;

import com.google.gson.Gson;
import com.hjq.permissions.IPermissionInterceptor;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.PermissionFragment;
import com.hjq.permissions.XXPermissions;
import com.keqiang.base.GlobalParamUtils;
import com.keqiang.base.ImageUtils;
import com.keqiang.base.Logger;
import com.keqiang.base.widget.dialog.DialogUtils;
import com.keqiang.base.widget.dialog.OnTwoBtnClickListener;
import com.keqiang.filepicker.DefaultOpenPath;
import com.keqiang.filepicker.FilePicker;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import androidx.activity.ComponentActivity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;

import com.keqiang.filepicker.StringRes;
import com.keqiang.filepicker.ZhStringRes;

import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import keqiang.com.kq_flutter_core_widget.R;
import keqiang.com.kq_flutter_core_widget.interf.IFileProvider;
import me.zhouzhuo810.magpiex.cons.MIME;
import me.zhouzhuo810.magpiex.utils.CollectionUtil;

import com.keqiang.base.uri.Uri;

import org.jetbrains.annotations.NotNull;

/**
 * 原生文件或图片选择
 *
 * @author zhouzhuo810 2023/4/12 13:40
 */
public class NativeFilePickerChannel extends MethodChannel {
    
    // 通道id
    private static final String CHANNEL = "flutter.keqiang.com/filePicker";
    
    // 拍照
    private static final String METHOD_TAKE_PHOTO = "takePhoto";
    
    // 选择图片
    private static final String METHOD_PICK_IMAGES = "pickImages";
    
    // 选择文件
    private static final String METHOD_PICK_FILES = "pickFiles";
    
    private static final int REQUEST_CODE_APPLY_CAMERA_PERMISSION = 0x1003;
    private static final int REQUEST_CODE_TAKE_PHOTO = 0x1001;
    
    private ActivityPluginBinding mBinding;
    private PluginRegistry.ActivityResultListener mActivityResultListener;
    private Result mResult;
    /**
     * 相机拍照图片地址
     */
    private String takePhotoPath = null;
    private Integer mCompress;
    
    public NativeFilePickerChannel(@NonNull BinaryMessenger messenger) {
        super(messenger, CHANNEL);
        init();
    }
    
    private void init() {
        setMethodCallHandler((call, result) -> {
            Integer maxCount;
            Integer compress;
            switch (call.method) {
                case METHOD_TAKE_PHOTO:
                    // 拍照
                    compress = call.argument("compress");
                    takePhoto(result, compress);
                    break;
                case METHOD_PICK_IMAGES:
                    //选择图片
                    maxCount = call.argument("maxCount");
                    compress = call.argument("compress");
                    if (maxCount == null) {
                        maxCount = 1;
                    }
                    pickImages(result, maxCount, compress);
                    break;
                case METHOD_PICK_FILES:
                    // 选择文件
                    maxCount = call.argument("maxCount");
                    compress = call.argument("compress");
                    List<String> extensions = call.argument("extensions");
                    if (maxCount == null) {
                        maxCount = 1;
                    }
                    
                    String strRes = call.argument("stringRes");
                    StringRes stringRes = null;
                    try {
                        stringRes = new Gson().fromJson(strRes, LocalStringRes.class);
                    } catch (Exception e) {
                        //
                    }
                    
                    if (stringRes == null) {
                        stringRes = new LocalStringRes();
                    }
                    
                    pickFiles(result, extensions, maxCount, compress, stringRes);
                    break;
            }
        });
    }
    
    /**
     * 拍照
     */
    private void takePhoto(Result result, Integer compress) {
        mResult = result;
        mCompress = compress;
        XXPermissions.with(mBinding.getActivity())
            .permission(Permission.CAMERA, Permission.MANAGE_EXTERNAL_STORAGE)
            .interceptor(new IPermissionInterceptor() {
                
                @Override
                public void launchPermissionRequest(@NonNull Activity activity, @NonNull List<String> allPermissions, @Nullable OnPermissionCallback callback) {
                    IPermissionInterceptor thisInterceptor = this;
                    DialogUtils.showMsgDialog(mBinding.getActivity(), mBinding.getActivity().getString(R.string.base_refuse_permission_not_use_camera_hint), false, new OnTwoBtnClickListener() {
                        @Override
                        public void onLeftClick() {
                            onTakePhoto(2, "未授予权限", null);
                        }
                        
                        @Override
                        public void onRightClick() {
                            PermissionFragment.launch(
                                activity,
                                new ArrayList<>(allPermissions),
                                thisInterceptor,
                                callback
                            );
                        }
                    });
                }
                
            }).request(new OnPermissionCallback() {
                @Override
                public void onGranted(List<String> permissions, boolean all) {
                    if (all) {
                        goCameraView();
                    } else {
                        onTakePhoto(2, "未授予权限", null);
                    }
                }
                
                @Override
                public void onDenied(List<String> permissions, boolean never) {
                    if (never) {
                        DialogUtils.showMsgDialog(mBinding.getActivity(),
                            mBinding.getActivity().getString(R.string.base_set_use_camera_permission_hint), false, new OnTwoBtnClickListener() {
                                @Override
                                public void onLeftClick() {
                                    onTakePhoto(2, "未授予权限", null);
                                }
                                
                                @Override
                                public void onRightClick() {
                                    XXPermissions.startPermissionActivity(mBinding.getActivity(),
                                        permissions,
                                        REQUEST_CODE_APPLY_CAMERA_PERMISSION
                                    );
                                }
                            });
                    } else {
                        onTakePhoto(2, "未授予权限", null);
                    }
                }
            });
    }
    
    /**
     * 相机拍照结果回调
     */
    private void onTakePhoto(int code, String msg, Map<String, Object> dataMap) {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", code);
        resultMap.put("msg", msg);
        resultMap.put("data", dataMap);
        if (mResult != null) {
            try {
                //重复回调好像会闪退，try catch保险
                mResult.success(resultMap);
                mResult = null;
            } catch (Exception e) {
                //
            }
        }
        mCompress = null;
    }
    
    /**
     * 打开相机界面
     */
    private void goCameraView() {
        String cacheDirPath = GlobalParamUtils.getTakePhotoCachePath();
        if (mBinding.getActivity() instanceof IFileProvider) {
            cacheDirPath = ((IFileProvider) mBinding.getActivity()).getCacheDirPath();
        }
        File file = new File(cacheDirPath);
        if (!file.exists() && !file.mkdirs()) {
            onTakePhoto(0, mBinding.getActivity().getString(R.string.base_storage_not_enough_could_not_open_camera_hint), null);
            return;
        }
        
        String imageFileName = String.valueOf(System.currentTimeMillis());
        // 注意此处的目录需要在FileProvider的paths.xml中指定，否则FileProvider.getUriForFile会崩溃
        File image;
        try {
            image = File.createTempFile(imageFileName, ".jpg", file);
        } catch (IOException e) {
            Logger.printStackTrace(e);
            onTakePhoto(0, mBinding.getActivity().getString(R.string.base_storage_not_enough_could_not_open_camera_hint), null);
            return;
        }
        
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (intent.resolveActivity(mBinding.getActivity().getPackageManager()) != null) {
            String authorities = null;
            if (mBinding.getActivity() instanceof IFileProvider) {
                authorities = ((IFileProvider) mBinding.getActivity()).getAuthorities();
            }
            
            if (authorities == null) {
                authorities = GlobalParamUtils.getFileProviderAuthorities();
            }
            
            android.net.Uri uri = FileProvider.getUriForFile(mBinding.getActivity(), authorities, image);
            if (uri != null) {
                takePhotoPath = image.getAbsolutePath();
                intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
                mBinding.getActivity().startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
            } else {
                onTakePhoto(0, "找不到图片", null);
            }
        } else {
            onTakePhoto(0, "找不到相机", null);
        }
    }
    
    /**
     * 选择图片
     */
    private void pickImages(Result result, Integer maxCount, Integer compress) {
        FilePicker.with(mBinding.getActivity())
            .maxChosenCount(maxCount)
            .fileExtension("png", "jpeg", "jpg", "webp", "gif")
            .defaultOpenPath(DefaultOpenPath.IMAGE_PATH)
            // .spanCount(2)
            // .preferredLayout(PreferredLayout.GRID)
            .start(files -> {
                if (files == null) {
                    resultError(result, 2, "用户已取消");
                    return;
                }
                
                List<Map<String, Object>> dataList = new ArrayList<>();
                for (android.net.Uri file : files) {
                    dataList.add(uriToResult(Uri.fromAndroidUri(file), compress));
                }
                
                resultSuccess(result, "选择成功", dataList);
            });
    }
    
    private Map<String, Object> uriToResult(Uri uri, Integer compress) {
        Map<String, Object> dataMap = new HashMap<>();
        uri.queryAndroidInfo();
        String name = uri.getName();
        if (compress != null && compress > 0 && isImage(uri)) {
            uri = ImageUtils.compressImage(uri, compress);
            if (uri.getBindUri() != null) {
                // 压缩成功
                uri.queryAndroidInfo();
            }
        }
        
        dataMap.put("fileName", name);
        dataMap.put("filePath", uri.getPath());
        dataMap.put("fileLength", uri.getSize());
        String mime = uri.getMime();
        dataMap.put("mime", mime);
        if (name != null && !name.isEmpty()) {
            int indexOf = name.lastIndexOf('.');
            if (indexOf != -1) {
                String suffix = name.substring(indexOf);
                dataMap.put("suffix", suffix);
                if (mime == null || mime.isEmpty()) {
                    dataMap.put("mime", getMimeType(suffix));
                }
            }
        }
        return dataMap;
    }
    
    private boolean isImage(Uri uri) {
        String name = uri.getName();
        if (name == null) {
            return false;
        }
        name = name.toLowerCase();
        return name.endsWith(".png") || name.endsWith(".jpg")
            || name.endsWith(".jpeg") || name.endsWith(".webp");
    }
    
    private void resultError(Result result, int errorCode, String msg) {
        if (result == null) {
            return;
        }
        
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", errorCode);
        resultMap.put("msg", msg);
        result.success(resultMap);
    }
    
    private void resultSuccess(Result result, String msg, Object data) {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", 1);
        resultMap.put("msg", msg);
        resultMap.put("data", data);
        result.success(resultMap);
    }
    
    /**
     * 选择文件
     */
    private void pickFiles(Result result, List<String> extensions, Integer maxCount, Integer compress, StringRes stringRes) {
        FilePicker.setStringRes(stringRes);
        FilePicker filePicker = FilePicker.with(mBinding.getActivity())
            .maxChosenCount(maxCount);
        if (extensions != null && !extensions.isEmpty()) {
            filePicker.fileExtension(CollectionUtil.listToString(extensions));
        }
        filePicker.start(files -> {
            if (files == null) {
                resultError(result, 2, "用户已取消");
                return;
            }
            
            List<Map<String, Object>> dataList = new ArrayList<>();
            for (android.net.Uri file : files) {
                dataList.add(uriToResult(Uri.fromAndroidUri(file), compress));
            }
            
            resultSuccess(result, "选择成功", dataList);
        });
    }
    
    /**
     * 获取MIME
     */
    public String getMimeType(String suffix) {
        if (suffix == null) {
            return MIME.UNKNOWN;
        }
        
        // 没有uri，使用文件后缀来判断
        switch (suffix.toLowerCase()) {
            case ".png":
            case ".jpg":
            case ".jpeg":
                return "image/*";
            case ".xls":
                return MIME.XLS;
            case ".doc":
                return MIME.DOC;
            case ".pdf":
                return MIME.PDF;
            case ".docx":
                return MIME.DOCX;
            case ".xlsx":
                return MIME.XLSX;
            case ".zip":
                return MIME.ZIP;
            case ".ppt":
                return "application/mspowerpoint";
            case ".pptx":
                return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
        }
        return MIME.UNKNOWN;
    }
    
    public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
        Activity activity = binding.getActivity();
        mBinding = binding;
        if (activity instanceof ComponentActivity) {
            Lifecycle lifecycle = ((ComponentActivity) activity).getLifecycle();
            if (!lifecycle.getCurrentState().isAtLeast(Lifecycle.State.INITIALIZED)) {
                return;
            }
            
            lifecycle.addObserver((LifecycleEventObserver) (source, event) -> {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    
                    mBinding = null;
                }
            });
        }
        
        if (mActivityResultListener != null) {
            binding.addActivityResultListener(mActivityResultListener);
            return;
        }
        
        mActivityResultListener = (requestCode, resultCode, data) -> {
            if (requestCode == REQUEST_CODE_APPLY_CAMERA_PERMISSION) {
                if (XXPermissions.isGranted(
                    mBinding.getActivity(),
                    Permission.CAMERA,
                    Permission.WRITE_EXTERNAL_STORAGE)) {
                    goCameraView();
                }
                return true;
            }
            
            if (requestCode == REQUEST_CODE_TAKE_PHOTO) {
                if (resultCode == Activity.RESULT_OK) {
                    if (takePhotoPath != null) {
                        onTakePhoto(1, "拍照成功", uriToResult(Uri.fromFile(takePhotoPath), mCompress));
                    } else {
                        onTakePhoto(0, "图片路径错误", null);
                    }
                } else {
                    onTakePhoto(2, "拍照取消", null);
                }
                return true;
            }
            return false;
        };
        
        binding.addActivityResultListener(mActivityResultListener);
    }
    
    public static class LocalStringRes extends ZhStringRes {
        private String openDocument;
        private String lately;
        private String image;
        private String audio;
        private String video;
        private String download;
        private String rootFolder;
        private String document;
        private String zip;
        private String searchContent;
        private String noValidThirdAppForFilePreviewHint;
        private String filePreviewFailedHint;
        private String fileChosenCountFormat;
        private String search;
        private String emptyData;
        private String sortType;
        private String showHideFile;
        private String notShowHideFile;
        private String sortFileNameAz;
        private String sortFileNameZa;
        private String sortFileTimeAsc;
        private String sortFileTimeDesc;
        
        @NotNull
        @Override
        public String getAudio() {
            return audio == null ? super.getAudio() : audio;
        }
        
        @NotNull
        @Override
        public String getDocument() {
            return document == null ? super.getDocument() : document;
        }
        
        @NotNull
        @Override
        public String getDownload() {
            return download == null ? super.getDownload() : download;
        }
        
        @NotNull
        @Override
        public String getEmptyData() {
            return emptyData == null ? super.getEmptyData() : emptyData;
        }
        
        @NotNull
        @Override
        public String getFileChosenCountFormat() {
            return fileChosenCountFormat == null ? super.getFileChosenCountFormat() : fileChosenCountFormat;
        }
        
        @NotNull
        @Override
        public String getFilePreviewFailedHint() {
            return filePreviewFailedHint == null ? super.getFilePreviewFailedHint() : filePreviewFailedHint;
        }
        
        @NotNull
        @Override
        public String getImage() {
            return image == null ? super.getImage() : image;
        }
        
        @NotNull
        @Override
        public String getLately() {
            return lately == null ? super.getLately() : lately;
        }
        
        @NotNull
        @Override
        public String getNoValidThirdAppForFilePreviewHint() {
            return noValidThirdAppForFilePreviewHint == null ? super.getNoValidThirdAppForFilePreviewHint() : noValidThirdAppForFilePreviewHint;
        }
        
        @NotNull
        @Override
        public String getNotShowHideFile() {
            return notShowHideFile == null ? super.getNotShowHideFile() : notShowHideFile;
        }
        
        @NotNull
        @Override
        public String getOpenDocument() {
            return openDocument == null ? super.getOpenDocument() : openDocument;
        }
        
        @NotNull
        @Override
        public String getRootFolder() {
            return rootFolder == null ? super.getRootFolder() : rootFolder;
        }
        
        @NotNull
        @Override
        public String getSearch() {
            return search == null ? super.getSearch() : search;
        }
        
        @NotNull
        @Override
        public String getSearchContent() {
            return searchContent == null ? super.getSearchContent() : searchContent;
        }
        
        @NotNull
        @Override
        public String getShowHideFile() {
            return showHideFile == null ? super.getShowHideFile() : showHideFile;
        }
        
        @NotNull
        @Override
        public String getSortFileNameAz() {
            return sortFileNameAz == null ? super.getSortFileNameAz() : sortFileNameAz;
        }
        
        @NotNull
        @Override
        public String getSortFileNameZa() {
            return sortFileNameZa == null ? super.getSortFileNameZa() : sortFileNameZa;
        }
        
        @NotNull
        @Override
        public String getSortFileTimeAsc() {
            return sortFileTimeAsc == null ? super.getSortFileTimeAsc() : sortFileTimeAsc;
        }
        
        @NotNull
        @Override
        public String getSortFileTimeDesc() {
            return sortFileTimeDesc == null ? super.getSortFileTimeDesc() : sortFileTimeDesc;
        }
        
        @NotNull
        @Override
        public String getSortType() {
            return sortType == null ? super.getSortType() : sortType;
        }
        
        @NotNull
        @Override
        public String getVideo() {
            return video == null ? super.getVideo() : video;
        }
        
        @NotNull
        @Override
        public String getZip() {
            return zip == null ? super.getZip() : zip;
        }
    }
}
